package com.mokairui.threadpool;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static java.lang.Thread.sleep;

/**
 * @Description 任务调度线程池
 *      Timer: 过时不推荐, 简单易用但是有个很大的缺陷, 他是单线程执行任务
 * @Author Mokairui
 * @Since 2021/10/6
 */
@Slf4j(topic = "c.taskScheduler")
public class TaskScheduler {
    public static void main(String[] args) {
        // 1. 延时执行
        // 过时的调度方式
//        timerMethod();
        // 当前的推荐的调度方式
//        scheduleMethod();
        // 2. 每隔一段时间执行一次
//        scheduleTiming();
        // 3. 指定时间执行任务, 比如每周四什么时候执行
        cornScheduler();
    }

    private static void cornScheduler() {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 获取周四的时间
        LocalDateTime time = now.withHour(18).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.THURSDAY);
        System.out.println(time);
        // 如果当前时间 > 本周周四, 必须找到下周周四
        if (now.compareTo(time) > 0) {
            time = time.plusWeeks(1);
        }
        System.out.println(time);

        // initialDelay 戴白哦但钱时间和周四的时间差
        long initialDelay = Duration.between(now, time).toMillis();
        // period 一周的间隔时间
        long period = 1000 * 60 * 60 * 24 * 7;
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        pool.scheduleAtFixedRate(() -> {
            log.debug("running...");
        }, initialDelay, period, TimeUnit.MILLISECONDS);

    }

    private static void scheduleMethod() {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

        pool.schedule(() -> {
            log.debug("task 1");
            try {
                sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 1, TimeUnit.SECONDS);

        pool.schedule(() -> {
            log.debug("task 2");
        }, 1, TimeUnit.SECONDS);
    }

    private static void scheduleTiming() {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        log.debug("start...");
        // 参数: 执行内容, 延时时间, 间隔时间, 时间单位; 从任务开始就进入计时,时间到就执行下一个
        pool.scheduleAtFixedRate(() -> {
            log.debug("running...");
        }, 1, 1, TimeUnit.SECONDS);

        // 这个是在前一个任务执行完才会开始计时 1s 后再执行
        pool.scheduleWithFixedDelay(() -> {
            log.debug("running...");
        }, 1, 1, TimeUnit.SECONDS);
    }

    private static void timerMethod() {
        Timer timer = new Timer();

        TimerTask task1 = new TimerTask() {
            @SneakyThrows
            @Override
            public void run() {
                log.debug("task 1");
                sleep(2000);
            }
        };

        TimerTask task2 = new TimerTask() {
            @SneakyThrows
            @Override
            public void run() {
                log.debug("task 2");
            }
        };
        // 使用 timer 添加两个任务, 希望他们都在 1s 后执行
        // 但由于 timer 内只有一个线程来顺序执行队列中的任务, 因此 [任务1] 的延时, 影响了 [任务2] 的执行
        timer.schedule(task1, 1000);
        timer.schedule(task2, 1000);
    }
}
